﻿using System;
using System.Collections.Generic;
using Splendor_Server.script.logic.player;
using Splendor_Server.script.net;

namespace Splendor_Server.script.logic.room
{
    public class Room
    {
        public int id = 0;

        private int maxPlayer = 4; //最大玩家数

        private List<string> playerIds = new List<string>(); //房间玩家列表

        private string _ownerId = ""; //房主id

        private string _inTurnPId; //当前回合的玩家

        private int _turnOrder; //当前回合玩家在playerIds的Index

        private bool _isFinalTurn; //是否为最终回合

        private int _finalTurnIndex; //触发游戏结束的玩家在playerIds中的Index

        public enum RoomStatus
        {
            Wait,
            Start,
            End
        }

        private RoomStatus _roomStatus = RoomStatus.Wait; //状态

        private int isPrivate = 0;

        private int point = 0;

        private int rules = 0;

        private long _lastCheckTime; //上一次检查回合的时间

        private const float DefaultRoundCountDown = 46.0f; //一回合的时间

        public Room(int isPrivate, int point, int rules)
        {
            this.isPrivate = isPrivate;
            this.point = point;
            this.rules = rules;

            id = RoomManager.GetNextRoomId();
        }

        //添加玩家
        public bool AddPlayer(string pId)
        {
            Player player = PlayerManager.GetPlayer(pId);
            if (player == null)
            {
                Console.WriteLine("[{0}][RoomID:{1}]AddPlayer fail, player is null", NetManager.GetNowTime(), id);
                return false;
            }

            //准备状态才能加人
            if (_roomStatus != RoomStatus.Wait)
            {
                Console.WriteLine("[{0}][RoomID:{1}]AddPlayer fail, is battling", NetManager.GetNowTime(), id);
                return false;
            }

            //已经在房间里
            if (playerIds.Contains(pId))
            {
                Console.WriteLine("[{0}][RoomID:{1}]AddPlayer fail, already in this room", NetManager.GetNowTime(), id);
                return false;
            }

            //房间人数
            if (playerIds.Count >= maxPlayer)
            {
                Console.WriteLine("[{0}][RoomID:{1}]AddPlayer fail, reach maxPlayer", NetManager.GetNowTime(), id);
                return false;
            }

            playerIds.Add(pId);
            player.EnterRoom(id);
            //设置房主
            if (_ownerId == "")
            {
                _ownerId = player.GetPlayerId();
                player.SetOwner();
            }

            return true;
        }

        //是不是房主
        public bool IsOwner(Player player)
        {
            return player.GetPlayerId() == _ownerId;
        }

        public string GetOwner()
        {
            return _ownerId;
        }

        //删除玩家
        public bool RemovePlayer(string pId)
        {
            Player player = PlayerManager.GetPlayer(pId);
            if (player == null)
            {
                Console.WriteLine("[{0}][RoomID:{1}]RemovePlayer fail, player is null", NetManager.GetNowTime(), id);
                return false;
            }

            //没有在房间里
            if (!playerIds.Contains(pId))
            {
                Console.WriteLine("[{0}][RoomID:{1}]RemovePlayer fail, not in this room", NetManager.GetNowTime(), id);
                return false;
            }

            if (_roomStatus == RoomStatus.Start)
            {
                player.data.tot++;
            }

            //删除列表
            playerIds.Remove(pId);
            player.LeaveRoom();

            if (playerIds.Count == 0)
            {
                _roomStatus = RoomStatus.Wait;
                RoomManager.RemoveRoom(id);
            }
            //TODO 人数剩余一人时 停止游戏
            if (_ownerId == player.GetPlayerId())
                SwitchOwner();

            MsgLeaveRoom msg = new MsgLeaveRoom {pId = player.GetPlayerId(), result = 1, newOwner = _ownerId};
            Broadcast(msg);

            return true;
        }

        //选择房主
        private void SwitchOwner()
        {
            //选择第一个玩家 若房间没人设为空
            if (playerIds.Count > 0)
            {
                _ownerId = playerIds[0];
                PlayerManager.GetPlayer(_ownerId).SetOwner();
            }
        }

        //向房间内的玩家发送消息
        public void Broadcast(MsgBase msg)
        {
            foreach (string pId in playerIds)
            {
                PlayerManager.GetPlayer(pId).Send(msg);
            }
        }

        //向房间内的玩家发送消息，除了某玩家
        public void Broadcast(MsgBase msg, string except)
        {
            foreach (string pId in playerIds)
            {
                if (pId == except) continue;
                PlayerManager.GetPlayer(pId).Send(msg);
            }
        }

        //生成MsgGetRoomInfo协议
        public MsgBase ToGetRoomInfo()
        {
            MsgGetRoomInfo msg = new MsgGetRoomInfo();

            int num = playerIds.Count;
            msg.pInfos = new PlayerInfo[num];

            for (int i = 0; i < num; i++)
                msg.pInfos[i] = PlayerManager.GetPlayer(playerIds[i]).ToPlayerInfo();

            msg.rId = id;
            msg.point = point;
            msg.rules = rules;

            return msg;
        }

        public RoomInfo ToRoomInfo()
        {
            return new RoomInfo()
            {
                rId = id,
                pId = _ownerId,
                status = (int) _roomStatus,
                pNum = playerIds.Count,
                isPrivate = isPrivate,
                point = point,
                rules = rules
            };
        }

        //能否开战
        public StartBattleResult CheckStartBattle()
        {
            if (_roomStatus != RoomStatus.Wait)
                return StartBattleResult.IsBattling;
            if (playerIds.Count < 2)
                return StartBattleResult.NotEnoughPlayer;
            foreach (string pId in playerIds)
                if (!PlayerManager.GetPlayer(pId).IsPrepared())
                    return StartBattleResult.NotAllPrepare;
            StartBattle();
            return StartBattleResult.Successful;
        }

        public RoomStatus GetRoomStatus()
        {
            return _roomStatus;
        }

        public int GetRoomPlayerNum()
        {
            return playerIds.Count;
        }

        //开战
        private void StartBattle()
        {
            _roomStatus = RoomStatus.Start;
            _lastCheckTime = NetManager.GetTimeStamp();

            //打乱playerIds
            int n = playerIds.Count;
            for (int i = n - 1; i >= 0; i--)
            {
                int rand = new Random().Next(0, i);
                string tmp = playerIds[i];
                playerIds[i] = playerIds[rand];
                playerIds[rand] = tmp;
            }

            _turnOrder = 0;
            _inTurnPId = playerIds[_turnOrder];

            foreach (string pId in playerIds)
            {
                PlayerManager.GetPlayer(pId).StartBattle();
            }

            MsgEnterBattle msg = new MsgEnterBattle()
            {
                pIds = playerIds.ToArray(),
                first = _inTurnPId,
                rules = rules,
                extras = GameSpawn.GetExtraOrder(playerIds.Count),
                minesLv1 = GameSpawn.ShuffleArray(GameSpawn.mineOrderLevel1),
                minesLv2 = GameSpawn.ShuffleArray(GameSpawn.mineOrderLevel2),
                minesLv3 = GameSpawn.ShuffleArray(GameSpawn.mineOrderLevel3),
            };

            Broadcast(msg);
        }

        public bool IsInTurn(string pId)
        {
            return _inTurnPId == pId;
        }

        public void NextTurnPlayer()
        {
            _turnOrder++;
            if (_turnOrder >= playerIds.Count)
                _turnOrder = 0;

            if (_isFinalTurn && _turnOrder == _finalTurnIndex)
                EndBattle();

            _inTurnPId = playerIds[_turnOrder];
            MsgEndTurn msg = new MsgEndTurn() {pId = _inTurnPId};
            Broadcast(msg);
            _lastCheckTime = NetManager.GetTimeStamp();
        }

        //定时更新
        public void Update()
        {
            //状态判断
            if (_roomStatus != RoomStatus.Start)
                return;
            //时间判断
            if (NetManager.GetTimeStamp() - _lastCheckTime >= DefaultRoundCountDown)
                NextTurnPlayer();
        }

        //检测是否为最后一个回合
        public void CheckLastTurn(Player player)
        {
            if (player.gameData.point < point)
                return;

            _finalTurnIndex = playerIds.IndexOf(player.GetPlayerId());
            _isFinalTurn = true;

            MsgEnterLastTurn msg = new MsgEnterLastTurn();
            Broadcast(msg);
        }

        private void EndBattle()
        {
            _roomStatus = RoomStatus.End;

            int maxPoint = 0;
            string winner = "";
            foreach (string pId in playerIds)
            {
                Player player = PlayerManager.GetPlayer(pId);
                if (player.gameData.point > maxPoint)
                {
                    maxPoint = player.gameData.point;
                    winner = player.GetPlayerId();
                }
            }

            foreach (string pId in playerIds)
            {
                Player player = PlayerManager.GetPlayer(pId);
                if (player.GetPlayerId() == winner)
                    player.data.win++;
                player.data.tot++;
            }

            MsgBattleResult msg = new MsgBattleResult {pId = winner};
            _roomStatus = RoomStatus.Wait;
            Broadcast(msg);

            foreach (string pId in playerIds)
                RemovePlayer(pId);
        }
    }
}